package com.rg.inf.action;

import javax.servlet.ServletException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.ContextLoader;

import com.rd.sys.common.utils.JacksonMapper;
import com.rd.sys.common.utils.crypto.BASE64;
import com.rd.sys.common.utils.crypto.MD5;
import com.rd.sys.common.utils.crypto.TripleDES;
import com.rd.sys.dto.client.sync.MsgBody;
import com.rd.sys.dto.client.sync.MsgHeader;
import com.rd.sys.dto.commmon.base.EyeException;
import com.rd.sys.dto.commmon.base.EyeResult;
import com.rd.sys.dto.sys.user.UserInfoDto;
import com.rd.sys.dto.sys.user.UserSecurityDto;
import com.rd.sys.service.sys.user.UserAllInOneService;

public class DispatchAction {
    protected static final Logger logger = LoggerFactory.getLogger(DispatchAction.class);

    public String execute(String userCode, String message, Object... objs) throws ServletException, EyeException,
            Exception {
        EyeResult result = null;
        MsgHeader header = null;
        MsgBody body = null;
        UserSecurityDto userSecurity = null;

        /** 1. 根据用户编码获取用户安全信息 */
        UserAllInOneService userInfoService = (UserAllInOneService) ContextLoader.getCurrentWebApplicationContext()
                .getBean("userAllInOneServiceImpl");

        UserInfoDto userInfo = new UserInfoDto();
        userInfo.setUsercode(userCode);
        userInfo = userInfoService.selectUserInfo(userCode);
        if (userInfo == null) {
            throw new EyeException(EyeResult.ResultDefine.SYNC_USER_NOT_EXIST_ERROR);
        }
        userSecurity = userInfo.getSecurityInfo();

        try { // 只有找到对应用户成功后,才能给按协议格式返回错误码

            /** 2. 根据basekey解密消息 */
            String baseKey = BASE64.decode2String(userSecurity.getBasekey());// 基础密钥
            try {
                message = TripleDES.decrypt2String(baseKey, BASE64.decode(message)); // 根据基础密钥解密消息
                logger.debug("the original request message is :" + message);
            } catch (Exception ex) {
                logger.error("", ex);
                throw new EyeException(EyeResult.ResultDefine.SYNC_HEAD_RESOLVING_ERROR);
            }

            /** 3. 解析消息头 */
            try {
                header = (MsgHeader) JacksonMapper.json2Bean(message, MsgHeader.class);
            } catch (Exception ex) {
                logger.error("", ex);
                throw new EyeException(EyeResult.ResultDefine.SYNC_HEAD_DEFINED_ERROR);
            }

            /** 4. 对比MD5摘要,看是否有篡改 */
            String upKey = BASE64.decode2String(userSecurity.getUpkey()); // 上行接入密钥
            String md5 = MD5.encrypt(header.getMsgBody() + header.getBizCode() + header.getTimestamp() + upKey); // 根据协议计算方式为：MD5(消息体+BizCode+Timestamp+接入密钥)
            if (!md5.equals(header.getDigest())) {
                throw new EyeException(EyeResult.ResultDefine.SYNC_HEAD_DEFINED_ERROR);
            }

            /** 5. 根据bizcode解析出对应的消息体 */
            try {
                Class<? extends MsgBody> clazz = BizCodeUtils.buildMsgBody(header.getBizCode());
                body = (MsgBody) JacksonMapper.json2Bean(header.getMsgBody(), clazz);
            } catch (Exception ex) {
                logger.error("", ex);
                throw new EyeException(EyeResult.ResultDefine.SYNC_BODY_DEFINED_ERROR);
            }

            /** 6. 分发给对应的Action处理 */
            BaseExecuteAction action = BizCodeUtils.buildExecuteAction(header.getBizCode()).newInstance();
            result = action.execute(userInfo, body, objs);

        } catch (EyeException ex) {
            result = new EyeResult(ex.getResult());
        } catch (Exception ex) {
            logger.error("dispatch message to action error ", ex);
            result = new EyeResult(EyeResult.ResultDefine.COMMON_OTHER_ERROR_SERVER);
        }

        return buildResponseSimple(header, result, userSecurity);

    }

    /**
     * 组织响应报文
     * 
     * @param reqHeader
     * @param rspBody
     * @param userSecurity
     * @return
     */
    private String buildResponse(MsgHeader reqHeader, EyeResult rspBody, UserSecurityDto userSecurity)
            throws ServletException {
        try {
            /** 1.设置消息体 */
            String body = JacksonMapper.bean2Json(rspBody);
            reqHeader.setMsgBody(body);

            /** 2.计算MD5摘要 */
            String downKey = BASE64.decode2String(userSecurity.getDownkey()); // 下行接入密钥
            String md5 = MD5.encrypt(reqHeader.getMsgBody() + reqHeader.getBizCode() + reqHeader.getTimestamp()
                    + downKey);
            reqHeader.setDigest(md5);

            /** 3.整个消息3DES加密 */
            String message = JacksonMapper.bean2Json(reqHeader);
            String baseKey = BASE64.decode2String(userSecurity.getBasekey());// 基础密钥
            message = BASE64.encode(TripleDES.encrypt(baseKey, message)); // 根据基础密钥机密消息

            return message;
        } catch (Exception ex) {
            logger.error("", ex);
            throw new ServletException(ex);
        }
    }

    /**
     * 简单消息响应（只对消息体加密）
     * 
     * @param reqHeader
     * @param rspBody
     * @param userSecurity
     * @return
     * @throws ServletException
     */
    private String buildResponseSimple(MsgHeader reqHeader, EyeResult rspBody, UserSecurityDto userSecurity)
            throws ServletException {
        try {
            /** 1.消息3DES加密 */
            String message = JacksonMapper.bean2Json(rspBody);

            logger.debug("the original response message is :" + message);

            String baseKey = BASE64.decode2String(userSecurity.getBasekey());// 基础密钥
            message = BASE64.encode(TripleDES.encrypt(baseKey, message)); // 根据基础密钥机密消息

            return message;
        } catch (Exception ex) {
            logger.error("", ex);
            throw new ServletException(ex);
        }
    }
}
